package com.winit.openapi.oauth.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;

import com.alibaba.fastjson.JSONObject;
import com.winit.common.query.Page;
import com.winit.common.query.Searchable;
import com.winit.common.spi.command.GetByKeyCommand;
import com.winit.common.spi.context.CommandContext;
import com.winit.openapi.constants.ApiConstant;
import com.winit.openapi.constants.ErrorCode;
import com.winit.openapi.controller.BaseController;
import com.winit.openapi.exception.ApiBizException;
import com.winit.openapi.exception.ApiException;
import com.winit.openapi.model.RequestMsg;
import com.winit.openapi.model.ResponseMsg;
import com.winit.openapi.oauth.builder.APIOAuhtBuilder;
import com.winit.openapi.oauth.command.QueryUserAuthInfoByUserCommand;
import com.winit.openapi.oauth.command.QueryUserAuthInfoByClientCommand;
import com.winit.openapi.oauth.manager.APIClientManager;
import com.winit.openapi.oauth.manager.APIDeveloperManager;
import com.winit.openapi.oauth.manager.UserAuthorizationManager;
import com.winit.openapi.oauth.validator.APIOAuth2Validator;
import com.winit.openapi.oauth.vo.APIClientVo;
import com.winit.openapi.oauth.vo.APIDeveloperVo;
import com.winit.openapi.oauth.vo.UserAuthorizationVo;
import com.winit.openapi.util.ValidateUtil;
import com.winit.ums.spi.UmsUserService;
import com.winit.ums.spi.vo.user.UserVO;

@Controller
@RequestMapping(value = "/winit/oauth/client")
public class APIClientController extends BaseController {

    private Logger                   logger = LoggerFactory.getLogger(APIClientController.class);

    @Resource
    private APIClientManager         apiClientManager;

    @Resource
    private APIOAuhtBuilder          apiOAuhtBuilder;

    @Resource
    private UserAuthorizationManager userAuthorizationManager;

    @Resource
    private APIDeveloperManager      apiDeveloperManager;

    @Resource
    private UmsUserService           umsUserService;

    @RequestMapping(value = "/create")
    public String create(@ModelAttribute RequestMsg requestMsg) {

        Object obj = requestMsg.getData();
        if (obj instanceof JSONObject) {
            JSONObject json = (JSONObject) obj;
            APIOAuth2Validator.validateClientAdd(json);
            String clientName = json.getString("clientName");
            String developerAccount = json.getString("developerAccount");
            try {
                APIDeveloperVo developer = apiDeveloperManager.selectByAccount(developerAccount);
                if (developer == null) {
                    throw new ApiException(ErrorCode.OAUTH_DEVELOPER_NOT_EXISTS_ERROR);

                }

                if (apiClientManager.checkExists(developer.getId(), clientName)) {
                    throw new ApiException(ErrorCode.OAUTH_CLIENT_EXISTS_ERROR);
                }
                if (apiClientManager.checkClientCode(json.getString("clientCode")) == 1) {
                    throw new ApiException(ErrorCode.OAUTH_CLIENT_CODE_EXISTS_ERROR, json.getString("clientCode"));
                }
                APIClientVo vo = apiOAuhtBuilder.buildClientAdd(json, developer);

                apiClientManager.insertClient(vo);
            } catch (ApiBizException e) {
                logger.error("APIClientController->create client :error:{}", e);
                throw new ApiException(ErrorCode.OAUTH_CREATE_CLIENT_ERROR);
            }

        } else {
            throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }

        return SUCCESS;
    }

    @RequestMapping(value = "/update")
    public String update(@ModelAttribute RequestMsg requestMsg) {

        Object obj = requestMsg.getData();
        if (obj instanceof JSONObject) {
            JSONObject json = (JSONObject) obj;
            APIOAuth2Validator.validateClientUpdate(json);
            try {
                APIClientVo vo = apiClientManager.selectByClientKey(json.getString("clientId"));
                if (null == vo) {
                    throw new ApiException(ErrorCode.OAUTH_CLIENT_NOT_EXISTS_ERROR, json.getString("clientId"));
                }
                String clientName = json.getString("clientName");
                String clientCode = json.getString("clientCode");
                // 说明客户进行了clientName的修改,需要校验名称的重复性
                if (!vo.getClientName().equals(clientName.trim())) {
                    if (apiClientManager.checkExists(vo.getDeveloperId(), clientName)) {
                        throw new ApiException(ErrorCode.OAUTH_CLIENT_EXISTS_ERROR);
                    }
                    vo.setClientName(clientName);
                }
                if (!vo.getClientCode().equals(clientCode.trim())) {
                    if (apiClientManager.checkClientCode(json.getString("clientCode")) == 1) {
                        throw new ApiException(ErrorCode.OAUTH_CLIENT_CODE_EXISTS_ERROR, clientCode);
                    }
                    vo.setClientCode(clientCode);
                    // 更新应用code需要重新审核
                    // vo.setStatus("N");
                }
                apiOAuhtBuilder.buildClientUpdate(json, vo);

                apiClientManager.updateClient(vo);
            } catch (ApiBizException e) {
                logger.error("APIClientController->update client :error:{}", e);
                throw new ApiException(ErrorCode.OAUTH_CLIENT_UPDATE_ERROR);
            }

        } else {
            throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }

        return SUCCESS;
    }

    @RequestMapping(value = "/delete")
    public String delete(@ModelAttribute RequestMsg requestMsg) {

        Object obj = requestMsg.getData();
        if (obj instanceof JSONObject) {
            try {
                JSONObject json = (JSONObject) obj;
                ValidateUtil.validNotNull(json, "clientId");
                ValidateUtil.validMaxLength(json, "clientId", 100, true);
                String clientKey = json.getString("clientId");
                APIClientVo client = apiClientManager.selectByClientKey(clientKey);
                if (null == client) {
                    throw new ApiException(ErrorCode.OAUTH_CLIENT_NOT_EXISTS_ERROR, json.getString("clientId"));
                }

                int count = userAuthorizationManager.getUserCountByClient(client.getId());
                if (0 != count) {
                    throw new ApiException(ErrorCode.OAUTH_CLIENT_CANNOT_DELETE_ERROR);
                }

                apiClientManager.deleteClient(client.getId());
            } catch (ApiBizException e) {
                logger.error("APIClientController->delete client :error:{}", e);
                throw new ApiException(ErrorCode.OAUTH_CLIENT_DELETE_ERROR);
            }

        } else {
            throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }

        return SUCCESS;
    }

    @RequestMapping(value = "/queryClientDetail")
    public String queryClientDetail(@ModelAttribute RequestMsg requestMsg, @ModelAttribute ResponseMsg responseMsg) {
        Object obj = requestMsg.getData();
        if (obj instanceof JSONObject) {
            JSONObject json = (JSONObject) obj;
            ValidateUtil.validNotNull(json, "clientId");
            ValidateUtil.validMaxLength(json, "clientId", 100, true);
            String clientKey = json.getString("clientId");
            try {
                APIClientVo client = apiClientManager.selectByClientKey(clientKey);
                if (null == client) {
                    throw new ApiException(ErrorCode.OAUTH_CLIENT_NOT_EXISTS_ERROR, json.getString("clientId"));
                }
                List<UserAuthorizationVo> userAuriList = userAuthorizationManager.queryByClientId(client.getId());
                client.setUserList(userAuriList);
                Map<String, Object> data = apiOAuhtBuilder.buildClientDetail(client);
                data.put("userList", apiOAuhtBuilder.buildUserAuthResult(client.getUserList(), client));
                responseMsg.setData(data);
            } catch (ApiBizException e) {
                logger.error("APIClientController->queryClientDetail :error:{}", e);
                throw new ApiException(ErrorCode.OAUTH_CLIENT_QUERY_ERROR);
            }
        } else {
            throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }
        return SUCCESS;
    }

    @RequestMapping(value = "/queryClientName")
    public String queryClientName(@ModelAttribute RequestMsg requestMsg, @ModelAttribute ResponseMsg responseMsg) {
        Object obj = requestMsg.getData();
        if (obj instanceof JSONObject) {
            JSONObject json = (JSONObject) obj;
            ValidateUtil.validNotNull(json, "clientId");
            ValidateUtil.validMaxLength(json, "clientId", 100, true);
            String clientKey = json.getString("clientId");
            try {
                APIClientVo client = apiClientManager.selectByClientKey(clientKey);
                if (null == client) {
                    throw new ApiException(ErrorCode.OAUTH_CLIENT_NOT_EXISTS_ERROR, json.getString("clientId"));
                }

                Map<String, String> data = new HashMap<String, String>();
                data.put("clientName", client.getClientName());
                responseMsg.setData(data);
            } catch (ApiBizException e) {
                logger.error("APIClientController->queryClientName :error:{}", e);
                throw new ApiException(ErrorCode.OAUTH_CLIENT_QUERY_ERROR);
            }
        } else {
            throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }
        return SUCCESS;
    }

    @RequestMapping(value = "/queryUserListByClient")
    public String queryUserListByClient(@ModelAttribute RequestMsg requestMsg, @ModelAttribute ResponseMsg responseMsg) {
        Object obj = requestMsg.getData();
        if (obj instanceof JSONObject) {
            JSONObject json = (JSONObject) obj;
            ValidateUtil.validNotNull(json, "clientId");
            ValidateUtil.validMaxLength(json, "clientId", 100, true);
            APIClientVo vo = apiClientManager.selectByClientKey(json.getString("clientId"));
            if (null == vo) {
                throw new ApiException(ErrorCode.OAUTH_CLIENT_NOT_EXISTS_ERROR, json.getString("clientId"));
            }
            List<Long> clientIdList = new ArrayList<Long>();
            QueryUserAuthInfoByClientCommand command = new QueryUserAuthInfoByClientCommand();
            command.setCtx(CommandContext.getContext());
            clientIdList.add(vo.getId());
            command.setClientIdList(clientIdList);
            Searchable searchable = buildSearchablePageParams(json);
            command.setSearchable(searchable);

            Page<UserAuthorizationVo> list = userAuthorizationManager.findPageByClientId(command);

            Map<String, Object> data = new HashMap<String, Object>();
            int pageNo = searchable.getPage().getPageNumber() == 0 ? ApiConstant.PAGE_NO_DEFAULT : searchable.getPage()
                .getPageNumber();
            int pageSize = searchable.getPage().getPageSize() == 0 ? ApiConstant.PAGE_SIZE_DEFAULT : searchable.getPage()
                .getPageSize();

            data.put("pageNo", pageNo);
            data.put("pageSize", pageSize);
            data.put("total", list.total);
            data.put("list", apiOAuhtBuilder.buildUserAuthResult(list.content, vo));
            responseMsg.setData(data);

        } else {
            throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }
        return SUCCESS;
    }

    @RequestMapping(value = "/queryClientListByUser")
    public String queryClientListByUser(@ModelAttribute RequestMsg requestMsg, @ModelAttribute ResponseMsg responseMsg) {
        Object obj = requestMsg.getData();
        if (obj instanceof JSONObject) {
            JSONObject json = (JSONObject) obj;
            ValidateUtil.validNotNull(json, "userName");
            ValidateUtil.validMaxLength(json, "userName", 100, true);
            String userName = json.getString("userName");
            GetByKeyCommand<String> userCommand = new GetByKeyCommand<String>();
            userCommand.setSearchKey(userName);
            UserVO userVo = umsUserService.queryByUsername(userCommand);
            if (userVo == null) {
                throw new ApiException(ErrorCode.USER_NOT_FOUND);
            }

            QueryUserAuthInfoByUserCommand command = new QueryUserAuthInfoByUserCommand();
            command.setCtx(CommandContext.getContext());
            command.setUserId(userVo.getId());
            Searchable searchable = buildSearchablePageParams(json);
            command.setSearchable(searchable);

            Page<UserAuthorizationVo> userAuthList = userAuthorizationManager.findPageByUserId(command);
            if (null == userAuthList || userAuthList.content == null || userAuthList.content.size() == 0) {
                throw new ApiException(ErrorCode.OAUTH_CLIENT_NOT_EXISTS_ERROR, json.getString("clientId"));
            }

            List<Map<String, Object>> clientDataList = new ArrayList<Map<String, Object>>();
            for (UserAuthorizationVo userAuthVo : userAuthList.content) {
                APIClientVo clientVo = apiClientManager.getById(userAuthVo.getClientId());
                if (clientVo != null) {
                    clientDataList.add(apiOAuhtBuilder.buildClientInfoForSellerPortal(clientVo, userAuthVo));
                }
            }
            Map<String, Object> data = new HashMap<String, Object>();
            int pageNo = searchable.getPage().getPageNumber() == 0 ? ApiConstant.PAGE_NO_DEFAULT : searchable.getPage()
                .getPageNumber();
            int pageSize = searchable.getPage().getPageSize() == 0 ? ApiConstant.PAGE_SIZE_DEFAULT : searchable.getPage()
                .getPageSize();

            data.put("pageNo", pageNo);
            data.put("pageSize", pageSize);
            data.put("total", userAuthList.total);
            data.put("list", clientDataList);
            responseMsg.setData(data);

        } else {
            throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }
        return SUCCESS;
    }
}
